package org.vigor.lab.gateway.zuul;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * RedisRouteLocator
 * <p>
 * Redis 路由网关加载器
 * </p>
 *
 * @author Vigor Yuan
 */
public class RedisRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    public final Logger logger = LoggerFactory.getLogger(this.getClass());

    public static final String GLOBAL_KEY_REDIS = "sys-route";

    private StringRedisTemplate redisTemplate;

    private ZuulProperties properties;

    public RedisRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
    }

    @Override
    protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();
        // 从application.yml中加载路由信息
        routesMap.putAll(super.locateRoutes());
        // 从db中加载路由信息
        routesMap.putAll(locateRoutesFromRedis());
        // 优化一下配置,以/ 开头
        LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            // Prepend with slash if not already present.
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtils.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return values;
    }

    private Map<String, ZuulProperties.ZuulRoute> locateRoutesFromRedis() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();
        Set<Object> keys = redisTemplate.opsForHash().keys(GLOBAL_KEY_REDIS);
        if (CollectionUtils.isEmpty(keys)) {
            return new LinkedHashMap<>();
        }
        for (Object key : keys) {
            String pathKey = String.valueOf(key);
            Object o = redisTemplate.opsForHash().get(GLOBAL_KEY_REDIS, pathKey);
            ZuulProperties.ZuulRoute zuulRoute = JSON.parseObject(o.toString(), ZuulProperties.ZuulRoute.class);
            routesMap.put(zuulRoute.getPath(), zuulRoute);
            logger.debug("add route [{}]", zuulRoute.toString());
        }
        return routesMap;
    }

    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void refresh() {
        doRefresh();
    }
}
